﻿using AutoMapper.Extensions.ExpressionMapping;
using BCCommon;
using BCService;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.Text.Unicode;
using System.Text.Encodings.Web;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Filters;
using BCTMSRESTful.Configs;
using BCTMSRESTful.Configs.Redis;
using BCTMSRESTful.Configs.Kafka;
using BCTMSRESTful.Controllers;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System.Globalization;
using Newtonsoft.Json.Converters;
using System.Text.Json.Serialization;
//using System.Text.Json.Serialization;

namespace BCTMSRESTful
{
    /// <summary>
    /// 站点启动程序
    /// </summary>
    public class Startup
    {
        /// <summary>
        /// 项目启动程序
        /// </summary>
        /// <param name="configuration">配置文件</param>
        public Startup(IConfiguration configuration)
        {
            this.Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(new LogHelper());
            // 解除文件上传大小限制
            services.Configure<FormOptions>(x =>
            {
                x.ValueCountLimit = int.MaxValue;
                x.ValueLengthLimit = int.MaxValue;
                x.MultipartBodyLengthLimit = int.MaxValue;
                x.MemoryBufferThreshold = int.MaxValue;
            });

            services.AddMvc(options =>
            {
                options.Filters.Add(typeof(StatisticsRequestAttribute));
                options.Filters.Add(typeof(HandlerErrorAttribute));
                options.Filters.Add(typeof(RequireModelValidateAttribute));
                options.ValueProviderFactories.Add(new JQueryQueryStringValueProviderFactory());
            })
            .AddJsonOptions(options =>
            {
                //格式化日期时间格式
                options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());
                //数据格式首字母小写
                options.JsonSerializerOptions.PropertyNamingPolicy = new JsonSnakeCaseNamingPolicy();
                ////数据格式原样输出
                //options.JsonSerializerOptions.PropertyNamingPolicy = null;
                //取消Unicode编码
                options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
                //忽略空值
                options.JsonSerializerOptions.IgnoreNullValues = true;
                //允许额外符号
                options.JsonSerializerOptions.AllowTrailingCommas = true;
                //反序列化过程中属性名称是否使用不区分大小写的比较
                options.JsonSerializerOptions.PropertyNameCaseInsensitive = false;
            })
            .AddNewtonsoftJson(options =>
            {
                //ProcessDictionaryKeys = false不能改为true,否则工作流自定义表单将无法使用。
                options.SerializerSettings.ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy { ProcessDictionaryKeys = false, OverrideSpecifiedNames = true } };
                options.SerializerSettings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
                options.SerializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeLocal, DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });
                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            });

            //枚举值显示
            services.AddControllers().AddJsonOptions(options =>
                options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
            //services.AddRouting(options => options.LowercaseUrls = false);
            // 允许跨域
            services.AddCors(options => options.AddPolicy("any", p => p.WithOrigins("*").AllowAnyMethod().AllowAnyHeader()));
            // JWT 选项
            services.AddJwtAuthentication();
#if DEBUG
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("TMSAdmin", new OpenApiInfo { Title = "管理端-TMS", Version = "v1" });
                options.SwaggerDoc("Default", new OpenApiInfo { Title = "未分类", Version = "v1" });
                options.SwaggerDoc("Admin", new OpenApiInfo { Title = "管理端", Version = "v1" });
                options.SwaggerDoc("AdminTrading", new OpenApiInfo { Title = "管理端-销售系统", Version = "v1" });
                options.SwaggerDoc("CRMAdmin", new OpenApiInfo { Title = "管理端-客户管理系统", Version = "v1" });
                options.SwaggerDoc("MakeStaticPage", new OpenApiInfo { Title = "管理端-生成静态模块", Version = "v1" });

                options.SwaggerDoc("ClientApp", new OpenApiInfo { Title = "手机应用-用户端", Version = "v1" });
                options.SwaggerDoc("DriverApp", new OpenApiInfo { Title = "手机应用-司机端", Version = "v1" });
                //options.SwaggerDoc("PartnerApp", new OpenApiInfo { Title = "手机应用-合伙人端", Version = "v1" });
                //options.SwaggerDoc("StaffApp", new OpenApiInfo { Title = "手机应用-员工端", Version = "v1" });


                //options.SwaggerDoc("SaleAdmin", new OpenApiInfo { Title = "管理端-汽贸销售系统", Version = "v1" });
                //options.SwaggerDoc("SaleFinanceAdmin", new OpenApiInfo { Title = "管理端-汽贸财务系统", Version = "v1" });
                //options.SwaggerDoc("FreightFinance", new OpenApiInfo { Title = "管理端-物流财务系统", Version = "v1" });
                options.SwaggerDoc("OAAdmin", new OpenApiInfo { Title = "管理端-工作流系统", Version = "v1" });

                //options.SwaggerDoc("PartnerFinance", new OpenApiInfo { Title = "合伙人财务系统", Version = "v1" });

                options.CustomSchemaIds(type => type.FullName);
                options.OperationFilter<SecurityRequirementsOperationFilter>();
                //options.DocumentFilter<LowercaseDocumentFilter>();
                options.MapTypes();

                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "BCCommon.xml"));
                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "BCDto.xml"));
                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "BCTMSRESTful.xml"));
                options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                {
                    Name = "Authorization",
                    In = ParameterLocation.Header,//query header body path formData
                    Scheme = "bearer",
                    Type = SecuritySchemeType.Http,
                    BearerFormat = "JWT",
                    Description = "访问令牌。"
                });
                options.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
                        },
                        new List<string>()
                    }
                });
            });
#endif
            
            services.AddMySql(option =>
            {
                option.MasterConnectionString = Configuration["MySqlConnectionString"];
                option.SlaveConnectionString = Configuration["MySqlConnectionString"];
            });
            services.AddMongodb(options =>
            {
                options.MongodbClusterEnabled = Configuration["MongoDB:MongodbClusterEnabled"];
                options.ConnectionString = Configuration["MongoDB:ConnectionString"];
                options.Database = Configuration["MongoDB:Database"];
                options.ServerAddress = Configuration["MongoDB:ServerAddress"];
                options.ReplicaSetName = Configuration["MongoDB:ReplicaSetName"];
                options.TimeOut = Configuration["MongoDB:TimeOut"];
            });
            services.AddRedis(options =>
            {
                if (bool.TryParse(Configuration["EnableRedis"], out bool enableRedis))
                {
                    options.EnableRedis = enableRedis;
                }
                options.RedisConnectionString = Configuration["RedisConnectionString"];
                options.RedisDatabaseNo = Configuration["RedisDatabaseNo"];
            });

            services.AddKafka(options =>
            {
                options.KafkaConnectionString = Configuration["KafkaConnectionString"];
                options.KafkaEnvironmentType = Configuration["KafkaEnvironmentType"];
            });

            services.AddSingleton(typeof(IConfiguration), this.Configuration);
            services.AddTimedJob();
            services.AddHttpContextAccessor();
            services.AddScoped<IApplicationContextService, WebContextService>(); // 添加 WebContextService，以方便在 Service 中访问客户端和用户信息。
            services.AddScoped<IWebSocketContextService, WebSocketContextService>();
            services.AddServices();

            #region 模型映射
            var configuration = new AutoMapper.MapperConfiguration(cfg =>
            {
                cfg.AddMaps(Assembly.Load(new AssemblyName("BCService")));
                cfg.AddExpressionMapping();
            });
            configuration.CompileMappings();
            BCService.Utils.MapperExtension.Mapper = configuration.CreateMapper();

            var workflowConfiguration = new AutoMapper.MapperConfiguration(cfg =>
            {
                cfg.AddMaps(Assembly.Load(new AssemblyName("BCWorkflowEngine")));
                cfg.AddExpressionMapping();
            });
            configuration.CompileMappings();

            BCWorkflowEngine.Utils.MapperExtension.Mapper = workflowConfiguration.CreateMapper();
            #endregion
        }

        /// <summary>
        /// 运行时调用配置来设置请求管道
        /// </summary>
        /// <param name="app">应用构建接口对象</param>
        /// <param name="env">主机环境接口对象</param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseTimedJob();
            app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto });

            //if (bool.TryParse(Configuration["EnabledBusinessFlowEngine"], out bool enabledBusinessFlowEngine) && enabledBusinessFlowEngine)
            //{
            //    var businessFlowTask = app.ApplicationServices.GetService<IBusinessFlowTask>();

            //    businessFlowTask.AddBusinessFlowRecord();
            //    businessFlowTask.PushBusinessFlow();
            //}

            if (bool.TryParse(Configuration["EnabledWeChat"], out bool enabledWeChat) && enabledWeChat)
            {
                //微信基本信息设置
                app.ConfigureWeChat(Configuration);
            }

            app.UseWebSockets(new WebSocketOptions
            {
                KeepAliveInterval = TimeSpan.FromSeconds(120)
            });

            //加入websocket
            if (Convert.ToBoolean(Configuration["WebSocket:Enabled"]))
            {
                app.UseWebSocket("/ws");
            }

#if DEBUG
            app.UseSwagger();
            app.UseSwaggerUI(options =>
            {
                options.RoutePrefix = "docs";

                var swagger = $@"{Directory.GetCurrentDirectory()}{Path.DirectorySeparatorChar}wwwroot{Path.DirectorySeparatorChar}swagger.template.html";

                if (File.Exists(swagger))
                {
                    options.IndexStream = () => new FileStream(swagger, FileMode.Open);
                }
                options.SwaggerEndpoint("/swagger/TMSAdmin/swagger.json", "管理端-TMS");

                options.SwaggerEndpoint("/swagger/Default/swagger.json", "未分类");
                options.SwaggerEndpoint("/swagger/Admin/swagger.json", "管理端");
                options.SwaggerEndpoint("/swagger/AdminTrading/swagger.json", "管理端-销售系统");
                options.SwaggerEndpoint("/swagger/CRMAdmin/swagger.json", "管理端-客户管理系统");
                options.SwaggerEndpoint("/swagger/MakeStaticPage/swagger.json", "管理端-生成静态模块");

                options.SwaggerEndpoint("/swagger/ClientApp/swagger.json", "手机应用-用户端");
                options.SwaggerEndpoint("/swagger/DriverApp/swagger.json", "手机应用-司机端");
                //options.SwaggerEndpoint("/swagger/PartnerApp/swagger.json", "手机应用-合伙人端");
                //options.SwaggerEndpoint("/swagger/StaffApp/swagger.json", "手机应用-员工端");

                //options.SwaggerEndpoint("/swagger/Admin/swagger.json", "管理端");
                //options.SwaggerEndpoint("/swagger/SaleAdmin/swagger.json", "管理端-汽贸销售系统");
                //options.SwaggerEndpoint("/swagger/SaleFinanceAdmin/swagger.json", "管理端-汽贸财务系统");
                //options.SwaggerEndpoint("/swagger/FreightFinance/swagger.json", "管理端-物流财务系统");
                options.SwaggerEndpoint("/swagger/OAAdmin/swagger.json", "管理端-工作流系统");

                //options.SwaggerEndpoint("/swagger/PartnerFinance/swagger.json", "合伙人财务系统");



                options.InjectStylesheet("/styles/swagger.css");
            });

            app.UseDeveloperExceptionPage();
#endif
            app.UseRouting();
            app.UseStaticFiles();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseCors("any");
            app.UseHttpsRedirection();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
            GeneralContainer.Configuration = this.Configuration;
            GeneralContainer.ServiceProvider = app.ApplicationServices;

            //PDF转换文件地址配置
            //RotativaConfiguration.Setup(env);
        }
    }
}
